package com.mega.center.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.mega.center.auth.enums.msg.AuthMsgEnum;
import com.mega.center.system.enums.msg.SysMsgEnum;
import com.mega.center.system.mapper.UserMapper;
import com.mega.center.system.mapper.UserRoleMapper;
import com.mega.center.system.model.dto.ext.UserExt;
import com.mega.center.system.model.dto.query.UserQueryDTO;
import com.mega.center.system.model.entity.User;
import com.mega.center.system.model.entity.UserRole;
import com.mega.center.system.model.vo.UserDetailVO;
import com.mega.center.system.service.IMenuService;
import com.mega.center.system.service.IModuleService;
import com.mega.center.system.service.IRoleService;
import com.mega.center.system.service.IUserService;
import com.mega.common.core.constant.UserConstants;
import com.mega.common.core.enums.CommonMsgEnum;
import com.mega.common.core.enums.CommonStatus;
import com.mega.common.core.exception.BusinessException;
import com.mega.common.core.web.service.MegaBaseServiceImpl;
import com.mega.common.security.utils.SecurityUtils;
import com.mega.system.api.vo.ModuleVO;
import com.mega.system.api.vo.UserAuthInfo;
import com.mega.system.api.vo.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户表 服务实现
 *
 * @author Eric
 * @version 1.0
 * @since 2020-09-23
 */
@Service
public class UserServiceImpl extends MegaBaseServiceImpl<UserMapper, User> implements IUserService {

    @Value("${mega.default.password}")
    private String defaultPwd;

    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private IRoleService roleService;
    @Autowired
    private IMenuService menuService;
    @Autowired
    private IModuleService moduleService;

    /**
     * 新增用户表
     *
     * @param user 用户表实体类
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(UserExt user) {
        //验证用户名是否唯一
        Integer nameCount = this.count(Wrappers.<User>lambdaQuery()
                .eq(User::getUserName, user.getUserName()));
        if (nameCount != null && nameCount > 0) {
            throw new BusinessException(SysMsgEnum.USER_NAME_REPEAT);
        }
        //验证手机号码是否唯一
        if (StrUtil.isNotBlank(user.getMobilePhone())) {
            Integer phoneCount = this.count(Wrappers.<User>lambdaQuery()
                    .eq(User::getMobilePhone, user.getMobilePhone()));
            if (phoneCount != null && phoneCount > 0) {
                throw new BusinessException(SysMsgEnum.USER_PHONE_REPEAT);
            }
        }
        //验证邮箱是否唯一
        if (StrUtil.isNotBlank(user.getEmail())) {
            Integer emailCount = this.count(Wrappers.<User>lambdaQuery()
                    .eq(User::getEmail, user.getEmail()));
            if (emailCount != null && emailCount > 0) {
                throw new BusinessException(SysMsgEnum.USER_EMAIL_REPEAT);
            }
        }
        user.setStatus(CommonStatus.NORMAL.getCode());
        user.setPassword(SecurityUtils.encryptPassword(defaultPwd));
        //插入用户数据
        this.save(user);

        //保存用户角色数据
        if (CollectionUtil.isNotEmpty(user.getRolesCodes())) {
            List<UserRole> userRoleList = new ArrayList<>();
            user.getRolesCodes().forEach(v -> {
                userRoleList.add(new UserRole(user.getUserName(), v));
            });
            userRoleMapper.createBatch(userRoleList);
        }
    }

    /**
     * 编辑用户表
     *
     * @param user 用户表实体类
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(UserExt user) {
        //判断数据是否为空
        User queryEntity = this.getById(user.getId());
        if (queryEntity == null) {
            throw new BusinessException(CommonMsgEnum.DATE_NOT_EXIST);
        }
        //验证手机号码是否唯一
        if (!user.getMobilePhone().equals(queryEntity.getMobilePhone()) && StrUtil.isNotBlank(user.getMobilePhone())) {
            Integer phoneCount = this.count(Wrappers.<User>lambdaQuery()
                    .eq(User::getMobilePhone, user.getMobilePhone()));
            if (phoneCount != null && phoneCount > 0) {
                throw new BusinessException(SysMsgEnum.USER_PHONE_REPEAT);
            }
        }
        //验证邮箱是否唯一
        if (!user.getEmail().equals(queryEntity.getEmail()) && StrUtil.isNotBlank(user.getEmail())) {
            Integer emailCount = this.count(Wrappers.<User>lambdaQuery()
                    .eq(User::getEmail, user.getEmail()));
            if (emailCount != null && emailCount > 0) {
                throw new BusinessException(SysMsgEnum.USER_EMAIL_REPEAT);
            }
        }
        //更新数据
        this.updateById(user);

        //保存用户角色数据
        userRoleMapper.deleteByUserName(user.getUserName());
        if (CollectionUtil.isNotEmpty(user.getRolesCodes())) {
            List<UserRole> userRoleList = new ArrayList<>();
            user.getRolesCodes().forEach(v -> {
                userRoleList.add(new UserRole(user.getUserName(), v));
            });
            userRoleMapper.createBatch(userRoleList);
        }
    }

    /**
     * 根据id删除用户表
     *
     * @param id 主键值
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(Long id) {
        User user = this.getById(id);
        if (user != null) {
            checkUserAllowed(user.getUserName());
            this.removeById(id);
        }
    }

    /**
     * 分页查询
     *
     * @param page  分页参数
     * @param param 查询参数
     * @return
     */
    @Override
    public IPage<User> listOfPage(IPage<User> page, UserQueryDTO param) {
        return this.baseMapper.listOfPage(page, param);
    }

    /**
     * 校验用户是否允许操作
     *
     * @param userName 用户名
     */
    private void checkUserAllowed(String userName) {
        if (SecurityUtils.isAdmin(userName)) {
            throw new BusinessException(SysMsgEnum.NO_RIGHT_OPER_ADMIN);
        }
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param userName
     * @return
     */
    @Override
    public UserInfo getUserInfoByUserName(String userName) {
        return this.baseMapper.getUserInfoByUserName(userName);
    }

    /**
     * 修改密码
     *
     * @param userId
     * @param oldPwd
     * @param newPwd
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changePwd(Long userId, String oldPwd, String newPwd) {
        User user = this.getById(userId);
        if (user != null) {
            if (!SecurityUtils.matchesPassword(oldPwd, user.getPassword())) {
                throw new BusinessException(SysMsgEnum.USER_OLDPWD_ERROR);
            }
            user.setPassword(SecurityUtils.encryptPassword(newPwd));
            this.baseMapper.updateById(user);
        } else {
            throw new BusinessException(CommonMsgEnum.DATE_NOT_EXIST);
        }
    }

    /**
     * 重置密码
     *
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPwd(Long userId) {
        User user = new User();
        user.setId(userId);
        user.setPassword(SecurityUtils.encryptPassword(defaultPwd));
        this.baseMapper.updateById(user);
    }

    /**
     * 修改用户状态
     *
     * @param userId
     * @param status
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeUserStatus(Long userId, String status) {
        if (!status.equals(CommonStatus.NORMAL.getCode())
                && !status.equals(CommonStatus.BLOCKED.getCode())
                && !status.equals(CommonStatus.DISABLED.getCode())) {
            throw new BusinessException(SysMsgEnum.USER_STATUS_NOT_VALID, status);
        }
        User user = this.getById(userId);
        if (user != null) {
            checkUserAllowed(user.getUserName());
            user.setStatus(status);
            this.baseMapper.updateById(user);
        } else {
            throw new BusinessException(CommonMsgEnum.DATE_NOT_EXIST);
        }
    }

    /**
     * 获取用户详细信息
     *
     * @param userId
     * @return
     */
    @Override
    public UserDetailVO getUserDetailInfo(Long userId) {
        return Optional.ofNullable(this.getById(userId)).map(v -> {
            UserDetailVO userDetailVO = new UserDetailVO();
            BeanUtil.copyProperties(v, userDetailVO);
            return userDetailVO;
        }).orElseGet(() -> {
            throw new BusinessException(CommonMsgEnum.DATE_NOT_EXIST);
        });
    }

    /**
     * 获取用户角色权限
     *
     * @param userName
     * @return
     */
    @Override
    public Set<String> getUserRolePermission(String userName) {
        if (SecurityUtils.isAdmin(userName)) {
            Set<String> roles = new HashSet<>();
            roles.add(UserConstants.ADMIN_ROLE);
            return roles;
        } else {
            List<UserRole> userRoleList = userRoleMapper.selectList(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getUserName, userName));
            return userRoleList.stream().map(UserRole::getRoleCode).collect(Collectors.toSet());
        }
    }

    /**
     * 获取用户权限信息
     *
     * @param userName
     * @return
     */
    @Override
    public UserAuthInfo getUserAuthInfoForLogin(String userName) {
        return Optional.ofNullable(this.getUserInfoByUserName(userName)).map(u -> {
            UserAuthInfo userAuthInfo = new UserAuthInfo();
            userAuthInfo.setUser(u);

            // 角色集合
            userAuthInfo.setRoles(this.getUserRolePermission(userName));
            //获取用户模块数据
            List<ModuleVO> userModuleList = moduleService.listUserModule(userName);
            userAuthInfo.setModules(userModuleList);
            if (CollectionUtil.isNotEmpty(userModuleList)) {
                Set<String> userModuleCodes = userModuleList.stream().map(ModuleVO::getModuleCode).collect(Collectors.toSet());
                userAuthInfo.setPermissions(menuService.getUserPermissionByModules(userName, userModuleCodes));
            }
            return userAuthInfo;
        }).orElseGet(() -> {
            throw new BusinessException(AuthMsgEnum.USER_NOT_EXISTS, userName);
        });
    }
}
